﻿using System;
using System.Collections.Generic;
using System.Text;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.SyntaxEditor.Addons.DotNet.Ast;

namespace WindowsUserControl.Codes
{
    /// <summary>
    /// Provides the base class for an AST node.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Each AST node has a single parent and optional children.
    /// The nodes may be navigated by parent to child or child to parent.
    /// When a node is created, it initially has no parent node.
    /// </para>
    /// <para>
    /// AST nodes implement the visitor pattern.
    /// </para>
    /// </remarks>
    public abstract class AstNode : ActiproSoftware.SyntaxEditor.AstNodeBase
    {

        private byte contextID;

        /// <summary>
        /// Gets the minimum context ID that should be used in your code for AST nodes inheriting this class.
        /// </summary>
        /// <remarks>
        /// Base all your context ID constants off of this value.
        /// </remarks>
        protected const byte AstNodeContextIDBase = AstNode.ContextIDBase;

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>AstNode</c> class. 
        /// </summary>
        public AstNode() { }

        /// <summary>
        /// Initializes a new instance of the <c>AstNode</c> class. 
        /// </summary>
        /// <param name="textRange">The <see cref="TextRange"/> of the AST node.</param>
        public AstNode(TextRange textRange) : base(textRange) { }

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Accepts the specified visitor for visiting this node.
        /// </summary>
        /// <param name="visitor">The visitor to accept.</param>
        /// <remarks>This method is part of the visitor design pattern implementation.</remarks>
        public void Accept(AstVisitor visitor)
        {
            if (visitor.OnPreVisiting(this))
                this.AcceptCore(visitor);
            visitor.OnPostVisited(this);
        }

        /// <summary>
        /// Accepts the specified visitor for visiting a child node of this node.
        /// </summary>
        /// <param name="visitor">The visitor to accept.</param>
        /// <param name="childNode">The child node to visit.</param>
        /// <remarks>This method is part of the visitor design pattern implementation.</remarks>
        public void AcceptChild(AstVisitor visitor, AstNode childNode)
        {
            if (childNode != null)
                childNode.Accept(visitor);
        }

        /// <summary>
        /// Accepts the specified visitor for visiting the child nodes of this node.
        /// </summary>
        /// <param name="visitor">The visitor to accept.</param>
        /// <param name="nodeList">The list of child nodes to visit.</param>
        /// <remarks>This method is part of the visitor design pattern implementation.</remarks>
        public void AcceptChildren(AstVisitor visitor, IAstNodeList nodeList)
        {
            if (nodeList != null)
            {
                for (int index = 0; index < nodeList.Count; index++)
                {
                    if (nodeList[index] is AstNode)
                        ((AstNode)nodeList[index]).Accept(visitor);
                }
            }
        }

        /// <summary>
        /// Accepts the specified visitor for visiting this node.
        /// </summary>
        /// <param name="visitor">The visitor to accept.</param>
        /// <remarks>
        /// This method must be implemented by each AST node.  It will look like the following:
        /// <code>
        /// if (visitor.OnVisiting(this)) {
        /// 	// Visit children
        /// 	if (this.ChildNodeCount > 0)
        /// 		this.AcceptChildren(visitor, this.ChildNodes);
        /// }
        /// visitor.OnVisited(this);
        /// </code>
        /// </remarks>
        protected abstract void AcceptCore(AstVisitor visitor);

        /// <summary>
        /// Gets or sets a context value identifying the context of the AST node within its parent node.
        /// </summary>
        /// <remarks>
        /// The context ID value is typically defined on the parent AST node as a constant.
        /// </remarks>
        public override int ContextID
        {
            get
            {
                return contextID;
            }
            set
            {
                contextID = (byte)value;
            }
        }

        /// <summary>
        /// Gets the <see cref="SimpleNodeType"/> that identifies the type of node.
        /// </summary>
        /// <value>The <see cref="SimpleNodeType"/> that identifies the type of node.</value>
        public abstract SimpleNodeType NodeType { get; }

        /// <summary>
        /// Gets the image index that is applicable for displaying this node in a user interface control.
        /// </summary>
        /// <value>The image index that is applicable for displaying this node in a user interface control.</value>
        public override int ImageIndex
        {
            get
            {
                return (int)ActiproSoftware.Products.SyntaxEditor.IconResource.Keyword;
            }
        }

    }
}
